﻿using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RMS.Common
{
    public class RedisDb
    {
        //private static string[] aliReadWriteHosts = new[] {
        //        // "redis://Hewenlong123@123.56.72.214:6379"/*redis://密码@访问地址:端口*/
        //         //  "Hewenlong123@r-2ze693f636ed49f4.redis.rds.aliyuncs.com:6379",
        //           "Hewenlong123@47.93.38.132:6379"
        //         };
        //PooledRedisClientManager redisPoolManager = new PooledRedisClientManager(4500/*连接池个数*/, 5/*连接池超时时间(秒)*/, aliReadWriteHosts);
        private static string[] aliReadWriteHosts = new string[] { };
        static PooledRedisClientManager redisPoolManager;
        public RedisDb()
        {
            string redisHosts = ConfigHelper.GetAppValue("RedisHosts");
            var arry = redisHosts.Split(' ');
            aliReadWriteHosts = (from t in arry where !string.IsNullOrWhiteSpace(t) select t).ToArray();
            if (redisPoolManager == null)
            {
                redisPoolManager = new PooledRedisClientManager(500/*连接池个数*/, 10/*连接池超时时间(秒)*/, aliReadWriteHosts);
            }
        }


        #region 写入List<T>泛型集合,默认DB0
        /// <summary>  
        /// 写入List<T>泛型类  
        /// </summary>  
        /// <typeparam name="T">泛型</typeparam>  
        /// <param name="keys">键</param>  
        /// <param name="value">泛型集合</param>  
        /// <param name="dt">到期时间</param>  
        /// <param name="db">其他数据盘</param> 
        /// <returns>bool 是否成功</returns>
        public bool Set<T>(string keys, List<T> value, DBNum dbnum = DBNum.LoginUser)
            where T : class
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Set<List<T>>(keys, value);
            }
        }
        public bool Set<T>(string keys, List<T> value, TimeSpan ts, DBNum dbnum = DBNum.LoginUser)
            where T : class
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Set<List<T>>(keys, value, ts);
            }
        }
        #endregion

        #region 读取List<T>泛型集合,默认DB0
        /// <summary>  
        /// 读取List<T>泛型集合,默认DB0
        /// </summary>  
        /// <typeparam name="T">泛型</typeparam>  
        /// <param name="keys">键</param>  
        /// <param name="db">其他数据盘</param> 
        /// <returns>泛型集合</returns>
        public List<T> Get<T>(string keys, DBNum dbnum = DBNum.LoginUser)
        {
            if (string.IsNullOrWhiteSpace(keys))
            {
                return null;
            }
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Get<List<T>>(keys);
            }
        }
        #endregion

        #region 写入key/value,默认DB0
        /// <summary>  
        /// 写入key/value,默认DB0
        /// </summary>  
        /// <param name="keys">键</param>  
        /// <param name="value">值</param>  
        /// <param name="dt">到期时间</param>  
        /// <param name="db">其他数据盘</param>  
        /// <returns>bool 是否成功</returns>
        public bool Set(string keys, string value, DBNum dbnum = DBNum.LoginUser)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Set(keys, value);
            }
        }
        public bool Set(string keys, string value, TimeSpan ts, DBNum dbnum = DBNum.LoginUser)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Set(keys, value, ts);

            }
        }
        public bool SetT<T>(string keys, T value, DBNum dbnum = DBNum.LoginUser)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Set<T>(keys, value);
            }
        }
        public bool SetT<T>(string keys, T value, TimeSpan ts, DBNum dbnum = DBNum.LoginUser)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Set<T>(keys, value, ts);
            }
        }
        #endregion

        #region 读取key/value,默认DB0
        /// <summary>  
        /// 读取key/value,默认DB0
        /// </summary>  
        /// <param name="keys">键</param>  
        /// <param name="db">其他数据盘</param> 
        /// <returns>值</returns>
        public string Get(string keys, DBNum dbnum = DBNum.LoginUser)
        {
            if (string.IsNullOrWhiteSpace(keys))
            {
                return string.Empty;
            }
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.GetValue(keys);
            }
        }
        /// <summary>  
        /// 读取key/value,默认DB0
        /// </summary>  
        /// <param name="keys">键</param>  
        /// <param name="db">其他数据盘</param> 
        /// <returns>值</returns>
        public T GetT<T>(string keys, DBNum dbnum = DBNum.LoginUser)
        {
            if (string.IsNullOrWhiteSpace(keys))
            {
                return default(T);
            }
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Get<T>(keys);
            }
        }
        #endregion

        #region 删除指定key,默认DB0
        /// <summary>  
        /// 删除,默认DB0
        /// </summary>  
        /// <param name="keys">键</param>  
        /// <param name="dbnum">其他数据盘</param> 
        /// <returns>bool 是否成功</returns>
        public bool Del(string keys, DBNum dbnum = DBNum.LoginUser)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                return redisClient.Remove(keys);
            }
        }
        /// <summary>  
        /// 删除,默认DB0
        /// </summary>  
        /// <param name="keys">键集合</param>  
        /// <param name="dbnum">其他数据盘</param> 
        public void Del(IEnumerable<string> keys, DBNum dbnum = DBNum.LoginUser)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                redisClient.RemoveAll(keys);
            }
        }
        #endregion

        #region Redis锁相关操作
        /// <summary>
        /// Redis锁
        /// </summary>
        /// <param name="dbnum">记录锁的库</param>
        /// <param name="key">锁的键(Id等唯一键)</param>
        /// <param name="seconds">自动解锁时间(默认300秒)</param>
        /// <returns></returns>
        public bool Lock(LockObject obj, string key, int seconds = 300)
        {
            DBNum dbnum = DBNum.Lock;
            bool ret = false;
            key = string.Format("{0}_{1}", obj.ToString(), key);
            do
            {
                if (!Add<string>(key, "1", dbnum, TimeSpan.FromSeconds(seconds)))
                    Thread.Sleep(5);
                else
                    ret = true;
            } while (!ret);
            return ret;
        }
        /// <summary>
        /// Redis锁(仅1次尝试)
        /// </summary>
        /// <param name="dbnum">记录锁的库</param>
        /// <param name="key">锁的键(Id等唯一键)</param>
        /// <param name="seconds">自动解锁时间(默认300秒)</param>
        /// <returns></returns>
        public bool LockOnce(LockObject obj, string key, int seconds = 300)
        {
            DBNum dbnum = DBNum.Lock;
            bool ret = false;
            key = string.Format("{0}_{1}", obj.ToString(), key);
            ret = Add<string>(key, "1", dbnum, TimeSpan.FromSeconds(seconds));
            return ret;
        }
        /// <summary>
        /// 解Redis锁
        /// </summary>
        /// <param name="dbnum">记录锁的库</param>
        /// <param name="key">锁的键(Id等唯一键)</param>
        /// <returns></returns>
        public bool Unlock(LockObject obj, string key)
        {
            DBNum dbnum = DBNum.Lock;
            key = string.Format("{0}_{1}", obj.ToString(), key);
            return Del(key, dbnum);
        }
        #endregion

        #region 添加(如果key存在则返回false，添加成功返回true)
        /// <summary>
        /// 添加数据默认为db0，添加成功返回true，如果key存在则返回false
        /// </summary>
        /// <typeparam name="T">value类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="dbnum">db库</param>
        /// <param name="expiresAt">过多少秒释放</param>
        /// <returns></returns>
        public bool Add<T>(string key, T value, DBNum dbnum = DBNum.LoginUser, TimeSpan? expiresIn = null)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                if (expiresIn.HasValue)
                {
                    return redisClient.Add<T>(key, value, expiresIn.Value);
                }
                else
                {
                    return redisClient.Add<T>(key, value);
                }
            }
        }
        #endregion

        #region 创建RedisClient用于创建事务
        /// <summary>
        /// 创建RedisClient
        /// </summary>
        /// <param name="dbnum">库编码</param>
        /// <returns></returns>
        public RedisClient CreatClient(DBNum dbnum = DBNum.LoginUser)
        {
            int db = (int)dbnum;
            //RedisConfig.VerifyMasterConnections = false;//需要设置
            var redisClient = redisPoolManager.GetClient();
            if (db != 0)
            {
                ((RedisClient)redisClient).ChangeDb(db);
            }
            RedisNativeClient redisNativeClient = (RedisNativeClient)redisClient;
            //redisNativeClient.Client = null;//ApsaraDB for Redis不支持client setname所以这里需要显示的把client对象置为null
            return (RedisClient)redisClient;
        }
        #endregion
        /// <summary>
        /// 获取某个库下所有数据
        /// </summary>
        /// <param name="dbnum"></param>
        /// <returns></returns>
        public IDictionary<string, object> GetAll(DBNum dbnum)
        {
            IDictionary<string, object> result = new Dictionary<string, object>();
            using (var redisClient = CreatClient(dbnum))
            {
                var allkeys = redisClient.GetAllKeys();
                if (allkeys != null && allkeys.Count > 0)
                {
                    result = redisClient.GetAll<object>(allkeys);
                }

            }
            return result;
        }

        public void RemoveAll(DBNum dbnum)
        {
            using (var redisClient = CreatClient(dbnum))
            {
                var allkeys = redisClient.GetAllKeys();
                redisClient.RemoveAll(allkeys);
            }

        }


        #region redistest

        public bool Save<T>(string keys, T value, DBNum dbnum = DBNum.LoginUser)
           where T : class
        {
            //int db = (int)dbnum;
            //RedisConfig.VerifyMasterConnections = false;//需要设置
            //using (var redisClient = redisPoolManager.GetClient())
            //{
            //    if (db != 0)
            //    {
            //        ((RedisClient)redisClient).ChangeDb(db);
            //    }
            //    RedisNativeClient redisNativeClient = (RedisNativeClient)redisClient;
            //    redisNativeClient.Client = null;//ApsaraDB for Redis不支持client setname所以这里需要显示的把client对象置为null
            //redisClient.Set<T>(keys, value);
            //redisClient.Save();
            //return true;
            //}
            using (var redisClient = CreatClient(dbnum))
            {
                redisClient.Set<T>(keys, value);
                redisClient.Save();
            }
            return true;
        }

        //public T GetS<T>(string keys, DBNum dbnum = DBNum.LoginUser)
        //{
        //    int db = (int)dbnum;
        //    RedisConfig.VerifyMasterConnections = false;//需要设置
        //    // using (var redisClient = redisPoolManager.GetCacheClient())
        //    using (var redisClient = redisPoolManager.GetClient())
        //    {
        //        if (db != 0)
        //        {
        //            ((RedisClient)redisClient).ChangeDb(db);
        //        }
        //        RedisNativeClient redisNativeClient = (RedisNativeClient)redisClient;
        //        redisNativeClient.Client = null;//ApsaraDB for Redis不支持client setname所以这里需要显示的把client对象置为null
        //        return redisClient.Get<T>(keys);
        //    }
        //}


        #endregion

        #region 枚举
        /// <summary>
        /// Redis业务对照编号
        /// </summary>
        public enum DBNum
        {
            /// <summary>
            /// 登陆的用户
            /// </summary>
            LoginUser = 100,
            /// <summary>
            /// 锁
            /// </summary>
            Lock = 101,
        }
        /// <summary>
        /// 锁的类型
        /// </summary>
        public enum LockObject
        {
            InfoComment = 1,
            Vote = 2
        }
        #endregion
    }
}
